import hashlib
import io
import math
from ethpow import Miner
from encode import encode

HASH_ALGORITHM = 'sha512'
HASHER = hashlib.new(HASH_ALGORITHM)

NONCE_SIZE = 8

DIFFICULTY_ORDER = 0
ENCODING_ORDER = 32
DIFFICULTY = math.pow(ENCODING_ORDER, DIFFICULTY_ORDER)

DIFFICULTY_PHRASE = 'dankmemes'

main_chain = []


# for i in range(len(DIFFICULTY_PHRASE),len(encode(HASHER.digest()))):
#     DIFFICULTY_PHRASE += '0'

def hash_block(previous_hash, data, nonce):
        HASHER.update((str(previous_hash) + str(data) + str(nonce)).encode("utf-8"))
        return HASHER.digest()

def to_bytes(bytes_or_str):
    if isinstance(bytes_or_str, str):
        value = bytes_or_str.encode('utf-8')
    else:
        value = bytes_or_str
    return value    #Instance of bytes


class Block:
    def __init__(self, previous, data, nonce, img, difficulty):
        buffer = io.StringIO()
        self.img = img

        self.previous = previous
        self.data = data
        self.nonce = nonce
        self.bin_nonce = ''
        self.hash = ''
        if previous is not None:
            self.number = main_chain.index(previous)
        else:
            self.number = 1
        self.difficulty = difficulty

        previous_hash = ''
        if self.previous is not None:
            previous_hash = self.previous.get_hash()

        self.mining_hash = hash_block(previous_hash,self.data,self.nonce)

        if self.previous is None:
            self.height = 0
        else:
            self.height = self.previous.get_height() + 1

    def get_previous(self):
        return self.previous

    def get_data(self):
        return self.data

    def get_nonce(self):
        return self.nonce

    def get_bin_nonce(self):
        return self.bin_nonce

    def get_nonce_encoded(self):
        return self.nonce

    def get_hash(self):
        return self.hash

    def get_hash_encoded(self):
        # return encode_32(str(self.get_hash()))
        return encode(str(self.get_hash()))

    def get_height(self):
        return self.height

    def get_string(self):
        previous_hash = 'None'
        prev = self.get_previous()
        if prev is not None:
            previous_hash = prev.get_hash()
        return '----------Block %s----------\nNonce %s\nBin Nonce %s\nprev %s\nData\n----------\n%s\n----------\nHash %s\n----------End Block----------' \
               % (self.get_height(), self.get_nonce(), self.get_bin_nonce(), previous_hash, self.get_data(), self.get_hash())





def mine_block(previous, data, nonce_source, difficulty):
    while True:
        nonce, img = nonce_source.provide_nonce()
        blk = Block(previous, data, nonce, img, difficulty)
        m = Miner(blk)
        bin_nonce, mix_hash = m.mine()
        blk.bin_nonce = bin_nonce
        blk.hash = mix_hash
        if bin_nonce:
            return blk
